package com.olap.starter.controller.admin.luckycola.utils;

import cn.hutool.db.meta.MetaUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.olap.starter.common.util.DBType;
import lombok.extern.log4j.Log4j2;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.util.SelectUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.Map;

import static java.lang.Character.toUpperCase;

@Log4j2
public class SqlUtil {
    public static final String ALTER_TABLE = "ALTER TABLE ";

    private static final OracleQuery oracleQuery = new OracleQuery();

    public static String getDbType(JdbcTemplate jdbcTemplate) {
        return DBType.getType(jdbcTemplate);
    }

    /**
     * 获取sql
     * @param dataSource
     * @param tableName
     * @return
     * @throws JSQLParserException
     */
    public static String getSelectSql(DataSource dataSource, String tableName) throws JSQLParserException {
        String[] columns = MetaUtil.getColumnNames(dataSource, tableName);
        return SelectUtils.buildSelectFromTableAndExpressions(new Table(tableName), columns).toString();
    }

    public static String getMethodName(String fieldName) {
        if (!StringUtils.hasText(fieldName)) {
            throw new RuntimeException("输入字符串为空！");
        }
        char[] chars = fieldName.toCharArray();
        chars[0] = toUpperCase(chars[0]);
        return String.valueOf(chars);
    }

    public static DbType getDbType(String str) {
        if (!str.contains(":mysql:") && !str.contains(":cobar:")) {
            if (str.contains(":oracle:")) {
                return DbType.ORACLE;
            } else if (str.contains(":postgresql:")) {
                return DbType.POSTGRE_SQL;
            } else if (str.contains(":sqlserver:")) {
                return DbType.SQL_SERVER;
            } else if (str.contains(":db2:")) {
                return DbType.DB2;
            } else if (str.contains(":mariadb:")) {
                return DbType.MARIADB;
            } else if (str.contains(":sqlite:")) {
                return DbType.SQLITE;
            } else if (str.contains(":h2:")) {
                return DbType.H2;
            } else if (!str.contains(":kingbase:") && !str.contains(":kingbase8:")) {
                if (str.contains(":dm:")) {
                    return DbType.DM;
                } else if (str.contains(":zenith:")) {
                    return DbType.GAUSS;
                } else if (str.contains(":oscar:")) {
                    return DbType.OSCAR;
                } else if (str.contains(":firebird:")) {
                    return DbType.FIREBIRD;
                } else {
                    return str.contains(":xugu:") ? DbType.XU_GU : DbType.OTHER;
                }
            } else {
                return DbType.KINGBASE_ES;
            }
        } else {
            return DbType.MYSQL;
        }
    }

    /**
     * 是否默认字段
     *
     * @param defaultFlag
     * @return
     */
    public static boolean isDefault(Object defaultFlag) {
        return StringPool.ONE.equals(defaultFlag);
    }

    public static String getNewDbName(String databaseName, JdbcTemplate jdbcTemplate) {
        String sql = new MySqlQuery().getCatalog();
        if (DbType.ORACLE.getDb().equals(databaseName)) {
            sql = new OracleQuery().getCatalog();
        }
        log.info(sql);
        return jdbcTemplate.queryForObject(sql, String.class);
    }

    /**
     * 获取注释sql
     *
     * @param tableName
     * @param column
     * @param comment
     * @return
     */
    public static String getCommentSql(String tableName, String column, Object comment) {
        if (ObjectUtils.isEmpty(comment)) {
            throw new RuntimeException("数据库注释为空！");
        }
        String commentSql = " TABLE " + tableName;
        if (StringUtils.hasText(column)) {
            commentSql = " COLUMN " + tableName + StringPool.DOT + column;
        }
        return "COMMENT ON" + commentSql + " IS '" + comment + "'";
    }

    public static String getDropSql(String tableName, String column) {
        return SqlUtil.ALTER_TABLE + tableName + " DROP COLUMN " + column;
    }

    /**
     * 删除 欧莱普特殊建表字段
     *
     * @param tableName
     * @return
     */
    public static String getDropDefaultSql(String tableName) {
        return getDropSql(tableName, "欧莱普特殊建表字段");
    }

    public static String getAddSql(String tableName, String column, Object type) {
        return getAddAllSql(tableName, column, type, "", false);
    }

    public static String getAddDefaultSql(String tableName, String column, Object type, String defaultValue) {
        return getAddAllSql(tableName, column, type, defaultValue, false);
    }

    public static String getAddPkSql(String tableName, String column, Object type, boolean isPk) {
        return getAddAllSql(tableName, column, type, "", isPk);
    }

    public static String getRenameSql(String tableName, String column, Object source) {
        if (ObjectUtils.isEmpty(source)) {
            throw new RuntimeException("数据库原字段名为空！");
        }
        return SqlUtil.ALTER_TABLE + tableName + " RENAME COLUMN  " + source.toString().toUpperCase() + " TO " + column;
    }

    public static String getAddAllSql(String tableName, String column, Object type, String defaultValue, boolean isPk) {
        if (ObjectUtils.isEmpty(type)) {
            throw new RuntimeException("数据库字段类型为空！");
        }
        return SqlUtil.ALTER_TABLE + tableName + " ADD " + StringPool.LEFT_BRACKET + column + StringPool.SPACE + type + getDefaultSql(defaultValue) + getPkSql(isPk) + StringPool.RIGHT_BRACKET;
    }

    private static String getDefaultSql(String defaultValue) {
        if (StringUtils.hasText(defaultValue)) {
            return " DEFAULT " + defaultValue;
        }
        return "";
    }

    /**
     * 数据库修改字段类型及默认值
     *
     * @param tableName
     * @param column
     * @param type
     * @param defaultValue
     * @return
     */
    public static String getModifyAllSql(String tableName, String column, Object type, String defaultValue) {
        if (ObjectUtils.isEmpty(type)) {
            throw new RuntimeException("数据库字段类型为空！");
        }
        String modifySql = StringPool.LEFT_BRACKET + column + " " + type + StringPool.RIGHT_BRACKET;
        if (!ObjectUtils.isEmpty(defaultValue)) {
            modifySql = column + getDefaultSql(defaultValue);
        }
        return SqlUtil.ALTER_TABLE + tableName + " MODIFY " + modifySql;
    }

    private static String getPkSql(boolean isPk) {
        if (isPk) {
            return " PRIMARY KEY";
        }
        return "";
    }

    /**
     * 字段类型相等
     *
     * @param map
     * @param dataSourceMap
     * @param columnName
     * @return
     */
    public static boolean dateTypeEq(Map<String, Object> map, Map<String, Map<String, Object>> dataSourceMap, String columnName) {
        return org.apache.commons.lang3.StringUtils.equals(map.get(oracleQuery.fieldType()).toString(), dataSourceMap.get(columnName).get(oracleQuery.fieldType()).toString());
    }

    /**
     * 字段类型不相等
     *
     * @param map
     * @param dataSourceMap
     * @param columnName
     * @return
     */
    public static boolean dateTypeNotEq(Map<String, Object> map, Map<String, Map<String, Object>> dataSourceMap, String columnName) {
        return !dateTypeEq(map, dataSourceMap, columnName);
    }

    /**
     * 注释相等
     *
     * @param map
     * @param dataSourceMap
     * @param columnName
     * @return
     */
    public static boolean commentEq(Map<String, Object> map, Map<String, Map<String, Object>> dataSourceMap, String columnName) {
        return org.apache.commons.lang3.StringUtils.equals(map.get(oracleQuery.fieldComment()).toString(), dataSourceMap.get(columnName).get(oracleQuery.fieldComment()).toString());
    }

    /**
     * 注释不相等
     *
     * @param map
     * @param dataSourceMap
     * @param columnName
     * @return
     */
    public static boolean commentNotEq(Map<String, Object> map, Map<String, Map<String, Object>> dataSourceMap, String columnName) {
        return !commentEq(map, dataSourceMap, columnName);
    }

    public static String getType(String length) {
        return "VARCHAR2(" + length + ")";    }

    /**
     * 字段类型长度相等
     *
     * @param map
     * @param dataSourceMap
     * @param columnName
     * @return
     */
    public static boolean lengthEq(Map<String, Object> map, Map<String, Map<String, Object>> dataSourceMap, String columnName) {
        return org.apache.commons.lang3.StringUtils.equals(map.get("CHARACTER_MAXIMUM_LENGTH").toString(), dataSourceMap.get(columnName).get("CHARACTER_MAXIMUM_LENGTH").toString());
    }

    /**
     * 字段类型长度不相等
     *
     * @param map
     * @param dataSourceMap
     * @param columnName
     * @return
     */
    public static boolean lengthNotEq(Map<String, Object> map, Map<String, Map<String, Object>> dataSourceMap, String columnName) {
        return !lengthEq(map, dataSourceMap, columnName);
    }
}
